from unittest.mock import patch, ANY
from rest_api.rest_api_server.models.enums import AssignmentRequestTypes as ReqTypes
from rest_api.rest_api_server.tests.unittests.test_api_base import TestApiBase

AUTHORIZE_ACTION_METHOD = ('rest_api.rest_api_server.controllers.assignment'
                           '.AssignmentController._authorize_action_for_pool')


class TestAssignmentApiBase(TestApiBase):
    def setUp(self, version='v2'):
        super().setUp(version)
        self.cloud_acc_id = None
        _, self.organization = self.client.organization_create(
            {'name': "organization"})
        self.org_id = self.organization['id']
        self.org_pool_id = self.organization['pool_id']
        self.user_id = self.gen_id()
        self.employee = self._create_employee(self.user_id, self.org_id)
        self.update_default_owner_for_pool(self.org_pool_id,
                                           self.employee['id'])
        self.sub_pools = []
        for i in range(3):
            code, resp = self.client.pool_create(
                self.org_id,
                {'name': "sub_bu_%d" % i,
                 'parent_id': self.org_pool_id})
            self.assertEqual(code, 201)
            self.sub_pools.append(resp)
        self.user2_id = self.gen_id()
        self.employee2 = self._create_employee(self.user2_id, self.org_id)
        self.initial_count_assignments_empl = 1
        self.initial_count_assignments_empl2 = 0
        self._mock_auth_user(self.user_id)
        self.p_get_user_info.return_value = {
            'display_name': 'User', 'id': self.user_id,
            'email': 'john@smith.com', 'is_password_autogenerated': False}
        self.p_create_rule = patch(
            'rest_api.rest_api_server.controllers.rule.RuleController.'
            'create_rule').start()
        code, self.cluster_type = self.client.cluster_type_create(
            self.org_id, {'name': 'c_type', 'tag_key': 'tn'})
        self.assertEqual(code, 201)

    def _check_notification_calls(self, p_mock, times, *args, **kwargs):
        calls_count = 0
        for call in p_mock.mock_calls[:p_mock.call_count]:
            if call[1] == args:
                if kwargs.items() <= call[2].items():
                    calls_count += 1
        self.assertEqual(
            times, calls_count,
            "Expected calls count: %d\nActual %d" % (times, calls_count))

    def _create_employee(self, user_id, organization_id):
        valid_employee = {
            'name': 'TestUser_%s' % self.gen_id()[:8],
            'auth_user_id': user_id
        }
        code, employee = self.client.employee_create(organization_id,
                                                     valid_employee)
        self.assertEqual(code, 201)
        return employee

    def _get_assignment_requests(self):
        code, requests = self.client.assignment_request_list(
            organization_id=self.org_id)
        self.assertEqual(code, 200)
        return (requests['assignment_requests'][ReqTypes.INCOMING.value],
                requests['assignment_requests'][ReqTypes.OUTGOING.value])

    def _get_incoming_assignment_requests(self):
        code, requests = self.client.assignment_request_list(
            organization_id=self.org_id, req_type=ReqTypes.INCOMING.value)
        self.assertEqual(code, 200)
        return requests['assignment_requests'][ReqTypes.INCOMING.value]

    def _get_outgoing_assignment_requests(self):
        code, requests = self.client.assignment_request_list(
            organization_id=self.org_id, req_type=ReqTypes.OUTGOING.value)
        self.assertEqual(code, 200)
        return requests['assignment_requests'][ReqTypes.OUTGOING.value]

    def _get_assignments(self):
        code, assignments = self.client.assignment_list(
            organization_id=self.org_id)
        self.assertEqual(code, 200)
        return assignments['assignments']

    def _create_resource(self, employee_id=None, pool_id=None, tags=None):
        if not employee_id:
            employee_id = self.employee['id']
        if not pool_id:
            pool_id = self.org_pool_id
        if not self.cloud_acc_id:
            valid_aws_cloud_acc = {
                'name': 'test_credentials',
                'type': 'aws_cnr',
                'config': {
                    'access_key_id': 'key',
                    'secret_access_key': 'secret',
                    'config_scheme': 'create_report'
                }
            }
            self.p_configure = patch(
                'tools.cloud_adapter.clouds.aws.Aws.configure_report').start()
            code, cloud_acc = self.create_cloud_account(
                self.org_id, valid_aws_cloud_acc, auth_user_id=self.user_id)
            self.assertEqual(code, 201)
            self.cloud_acc_id = cloud_acc['id']
        self.valid_resource = {
            'cloud_resource_id': self.gen_id(),
            'name': 'test_resource',
            'resource_type': 'test_type',
            'employee_id': employee_id,
            'pool_id': pool_id
        }
        if tags:
            self.valid_resource['tags'] = tags
        code, resource = self.cloud_resource_create(
            self.cloud_acc_id, self.valid_resource)
        self.assertEqual(code, 201)
        return resource

    @staticmethod
    def _prepare_assign_req_body(resource_id, approver_id, message=None):
        return {'resource_id': resource_id,
                'message': message,
                'approver_id': approver_id}

    @staticmethod
    def _prepare_assign_body(resource_id, pool_id, owner_id=None):
        body = {'resource_id': resource_id,
                'pool_id': pool_id,
                'owner_id': owner_id}
        return body

    def _check_response(self, response, **kwargs):
        for key in kwargs:
            self.assertTrue(
                key in response,
                "Expected key `%s` in response.\nActual keys: %s" % (
                    key, list(response.keys())))
            self.assertEqual(
                response[key], kwargs[key],
                "Unexpected %s value in response" % key)

    def _test_params(self, call, params, *args, required_parameters=None,
                     entities_should_exist=None):
        data = params.copy()
        unexpected_param_name = "unexpected_param"
        data[unexpected_param_name] = self.gen_id()
        code, response = call(*args, data)
        self.assertEqual(code, 400)
        self.assertTrue('Unexpected parameters' in response['error']['reason'])
        self.assertTrue(unexpected_param_name in response['error']['reason'])
        if required_parameters:
            for param in required_parameters:
                data = params.copy()
                data.pop(param)
                code, response = call(*args, data)
                self.assertEqual(code, 400)
                self.assertEqual(response['error']['reason'],
                                 '%s is not provided' % param)
        if entities_should_exist:
            for param in entities_should_exist:
                data = params.copy()
                id = str(self.gen_id())
                data[param] = id
                code, response = call(*args, data)
                self.assertEqual(code, 400)
                self.assertTrue('%s %s doesn\'t exist' % (param, id)
                                in response['error']['reason'])
                self.assertTrue(response['error']['error_code'], 'OE0212')

    def _get_resources(self, filters=None):
        if not filters:
            filters = {}
        return list(self.resources_collection.find(filters))


class TestAssignmentApi(TestAssignmentApiBase):
    def setUp(self, version='v2'):
        super().setUp(version)
        self.resource = self._create_resource(employee_id=self.employee['id'],
                                              pool_id=self.org_pool_id)

    def test_create_assignments_request(self):
        """
        Basic create assignment request flow.
        Steps:
           - 1. Check initial count of assignment requests for user.
             Should be 0.
           - 2. Create assignment request for current user.
           - 3. Verify response code is 201.
           - 4. Verify count of incoming assignment requests is 1.
        """
        requests = self._get_incoming_assignment_requests()
        self.assertEqual(len(requests), 0)
        new_request = self._prepare_assign_req_body(
            resource_id=self.resource['id'],
            approver_id=self.employee2['id'],
            message="Test message")
        code, _ = self.client.assignment_request_create(self.org_id,
                                                        new_request)
        self.assertEqual(code, 201)
        with self.switch_user(self.user2_id):
            requests = self._get_incoming_assignment_requests()
        self.assertEqual(len(requests), 1)

    @patch(AUTHORIZE_ACTION_METHOD)
    def test_create_assignments_request_cluster(self, p_authorize):
        """
        Basic create assignment request flow.
        Steps:
           - 1. Check initial count of assignment requests for user.
             Should be 0.
           - 2. Create cluster dependent resource
           - 3. Assign cluster
           - 4. Create assignment request for current user.
           - 5. Verify response code is 201.
           - 6. Verify count of incoming assignment requests is 1.
        """
        p_authorize.return_value = True

        requests = self._get_incoming_assignment_requests()
        self.assertEqual(len(requests), 0)

        clustered_resource = self._create_resource(tags={'tn': 'tv'})
        new_request = self._prepare_assign_body(
            resource_id=clustered_resource['cluster_id'],
            pool_id=self.org_pool_id)
        code, _ = self.client.assignment_create(self.org_id, new_request)
        self.assertEqual(code, 201)

        new_request = self._prepare_assign_req_body(
            resource_id=clustered_resource['cluster_id'],
            approver_id=self.employee2['id'],
            message="Test message")
        code, _ = self.client.assignment_request_create(
            self.org_id, new_request)
        self.assertEqual(code, 201)
        with self.switch_user(self.user2_id):
            requests = self._get_incoming_assignment_requests()
        self.assertEqual(len(requests), 1)
        self.assertEqual(requests[0]['resource_id'], clustered_resource['cluster_id'])

    @patch(AUTHORIZE_ACTION_METHOD)
    def test_create_assignments_request_dependent(self, p_authorize):
        """
        Basic create assignment request flow.
        Steps:
           - 1. Check initial count of assignment requests for user.
             Should be 0.
           - 2. Create cluster dependent resource
           - 3. Assign cluster
           - 4. Create dependent resource assignment request for current user.
           - 5. Verify response code is 424.
        """
        p_authorize.return_value = True

        requests = self._get_incoming_assignment_requests()
        self.assertEqual(len(requests), 0)

        clustered_resource = self._create_resource(tags={'tn': 'tv'})
        new_request = self._prepare_assign_body(
            resource_id=clustered_resource['cluster_id'],
            pool_id=self.org_pool_id)
        code, _ = self.client.assignment_create(self.org_id, new_request)
        self.assertEqual(code, 201)

        new_request = self._prepare_assign_req_body(
            resource_id=clustered_resource['id'],
            approver_id=self.employee2['id'],
            message="Test message")
        code, response = self.client.assignment_request_create(
            self.org_id, new_request)
        self.assertEqual(code, 424)
        self.assertEqual(response['error']['error_code'], 'OE0464')

    @patch(AUTHORIZE_ACTION_METHOD)
    def test_get_assignment_requests(self, p_authorize):
        """
        Test GET assignment_requests output. Incoming and outgoing requests.
        Steps:
           - 1. Verify incoming/outgoing requests for user1 user2.
             Should be empty.
           - 1. Create assignment request user1 -> user2. Request1.
           - 2. Create assignment request user2 -> user1. Request2.
           - 3. Get incoming requests (user1). It should contain only Request2.
           - 4. Get outgoing requests (user1). It should contain only Request1.
           - 5. Get incoming requests (user2). It should contain only Request1.
           - 6. Get outgoing requests (user2). It should contain only Request2.
           - 7. Get all assignment requests for user1.
             - Verify Request2 in incoming section.
             - Verify Request1 in outgoing section.
        """
        p_authorize.return_value = True
        resource1 = self._create_resource(employee_id=self.employee['id'],
                                          pool_id=self.org_pool_id)
        resource2 = self._create_resource(employee_id=self.employee['id'],
                                          pool_id=self.org_pool_id)
        requests = self._get_incoming_assignment_requests()
        self.assertEqual(len(requests), 0)
        requests = self._get_outgoing_assignment_requests()
        self.assertEqual(len(requests), 0)

        request1 = self._prepare_assign_req_body(
            resource_id=resource1['id'],
            approver_id=self.employee2['id'],
            message="Test message")
        code, request1 = self.client.assignment_request_create(self.org_id,
                                                               request1)
        self.assertEqual(code, 201)
        request2 = self._prepare_assign_req_body(
            resource_id=resource2['id'],
            approver_id=self.employee['id'],
            message="Test message")
        with self.switch_user(self.user2_id):
            code, request2 = self.client.assignment_request_create(
                self.org_id, request2)
        requests = self._get_incoming_assignment_requests()
        self.assertEqual(len(requests), 1)
        self.assertEqual(requests[0]['id'], request2['id'])
        requests = self._get_outgoing_assignment_requests()
        self.assertEqual(len(requests), 1)
        self.assertEqual(requests[0]['id'], request1['id'])

        with self.switch_user(self.user2_id):
            requests = self._get_incoming_assignment_requests()
            self.assertEqual(len(requests), 1)
            self.assertEqual(requests[0]['id'], request1['id'])
            requests = self._get_outgoing_assignment_requests()
            self.assertEqual(len(requests), 1)
            self.assertEqual(requests[0]['id'], request2['id'])

        incoming, outgoing = self._get_assignment_requests()
        self.assertEqual(len(incoming), 1)
        self.assertEqual(incoming[0]['id'], request2['id'])
        self.assertEqual(len(outgoing), 1)
        self.assertEqual(outgoing[0]['id'], request1['id'])

    @patch(AUTHORIZE_ACTION_METHOD)
    def test_create_assignment(self, p_authorize):
        """
        Basic create assignment flow.
        Steps:
           - 1.Check initial count of assignment for user.
           - 2. Create resource.
           - 3. Check count of assignments for user.
           - 3. Create assignment for current user for created resource.
           - 4. Verify response code is 201.
           - 5. Verify count of assignments. Should be +1.
           - 6. Verify created time is 0.

        """
        assignments = self._get_assignments()
        self.assertEqual(len(assignments), self.initial_count_assignments_empl)
        resource = self._create_resource()
        assignments = self._get_assignments()
        self.assertEqual(len(assignments),
                         self.initial_count_assignments_empl + 1)
        new_request = self._prepare_assign_body(
            resource_id=resource['id'],
            pool_id=self.org_pool_id)
        p_authorize.return_value = True
        code, _ = self.client.assignment_create(self.org_id, new_request)
        self.assertEqual(code, 201)
        assignments = self._get_assignments()
        self.assertEqual(len(assignments),
                         self.initial_count_assignments_empl + 1)

    @patch(AUTHORIZE_ACTION_METHOD)
    def test_create_assignment_cluster(self, p_authorize):
        """
        Basic create cluster assignment request flow.
        Steps:
           - 1. Check initial count of assignment requests for user.
             Should be 1.
           - 2. Create cluster dependent resource
           - 3. Check count of assignment requests for user2. Should be 2.
           - 4. Assign cluster to other user
           - 5. Verify response code is 201.
           - 6. Verify count of assignments for user2
        """
        assignments = self._get_assignments()
        self.assertEqual(len(assignments), self.initial_count_assignments_empl)
        clustered_resource = self._create_resource(tags={'tn': 'tv'})
        assignments = self._get_assignments()
        self.assertEqual(len(assignments),
                         self.initial_count_assignments_empl + 1)
        new_request = self._prepare_assign_body(
            resource_id=clustered_resource['cluster_id'],
            pool_id=self.sub_pools[0]['id'], owner_id=self.employee2['id'])
        p_authorize.return_value = True
        code, _ = self.client.assignment_create(self.org_id, new_request)
        self.assertEqual(code, 201)
        with self.switch_user(self.user2_id):
            assignments = self._get_assignments()
        self.assertEqual(len(assignments),
                         self.initial_count_assignments_empl2 + 1)

    @patch(AUTHORIZE_ACTION_METHOD)
    def test_create_assignment_subresource(self, p_authorize):
        """
        Basic create assignment flow.
        Steps:
           - 1. Create cluster type definition.
           - 2. Create resource which will become cluster subresource.
           - 3. Create assignment for current user for subresource.
           - 4. Verify response code is 424.
        """
        clustered_resource = self._create_resource(tags={'tn': 'tv'})
        new_request = self._prepare_assign_body(
            resource_id=clustered_resource['id'],
            pool_id=self.org_pool_id)
        p_authorize.return_value = True
        code, response = self.client.assignment_create(self.org_id, new_request)
        self.assertEqual(code, 424)
        self.assertEqual(response['error']['error_code'], 'OE0464')

    @patch(AUTHORIZE_ACTION_METHOD)
    def test_create_assignment_idempotency(self, p_authorize):
        """
        Check idempotency of assignment creation.
        Steps:
           - 1. Check initial count of assignment for user2. Should be 0.
           - 2. Create assignment for current user2.
           - 3. Verify response code is 201.
           - 4. Verify count of assignments is 1.
           - 5. Repeat steps 3-4 with the same owner and pool.
           - 6. Verify count of assignments. It's still should be 1.
           - 7. Repeat step 5.
           - 8. Verify count of assignments. It's still should be 1.

        """
        with self.switch_user(self.user2_id):
            assignments = self._get_assignments()
            self.assertEqual(len(assignments),
                             self.initial_count_assignments_empl2)
            body = self._prepare_assign_body(resource_id=self.resource['id'],
                                             pool_id=self.org_pool_id)
            p_authorize.return_value = True

            code, assignment1 = self.client.assignment_create(
                self.org_id, body)
            self.assertEqual(code, 201)
            assignments = self._get_assignments()
            self.assertEqual(len(assignments),
                             self.initial_count_assignments_empl2 + 1)

            code, _ = self.client.assignment_create(self.org_id, body)
            self.assertEqual(code, 201)
            assignments = self._get_assignments()
            self.assertEqual(len(assignments),
                             self.initial_count_assignments_empl2 + 1)
            for assignment in assignments:
                self.assertEqual(assignment1, assignment)

            code, assignment2 = self.client.assignment_create(
                self.org_id, body)
            self.assertEqual(code, 201)
            assignments = self._get_assignments()
            self.assertEqual(len(assignments),
                             self.initial_count_assignments_empl2 + 1)
            for assignment in assignments:
                self.assertEqual(assignment2, assignment)
            self.assertEqual(assignment1, assignment2)

    @patch(AUTHORIZE_ACTION_METHOD)
    def test_create_assignment_another_owner(self, p_authorize):
        """
        Test for creating assignment for another user.
        Steps:
           - 1. Create resource.
           - 2. Check initial count of assignment for current user.
           - 3. Create assignment for another user (user2).
           - 4. Verify response code is 201.
           - 5. Verify count of assignments for current user.
             Should be the same.
           - 6. Verify count of assignments the target user. Should be +1.
           - 7. Verify created time is 0.

        """
        resource = self._create_resource()
        assignments = self._get_assignments()
        self.assertEqual(len(assignments),
                         self.initial_count_assignments_empl + 1)
        new_request = self._prepare_assign_body(
            resource_id=resource['id'],
            pool_id=self.org_pool_id,
            owner_id=self.employee2['id'])
        p_authorize.return_value = True
        code, _ = self.client.assignment_create(self.org_id, new_request)
        self.assertEqual(code, 201)
        assignments = self._get_assignments()
        self.assertEqual(len(assignments), self.initial_count_assignments_empl)
        with self.switch_user(self.user2_id):
            assignments = self._get_assignments()
            self.assertEqual(len(assignments),
                             self.initial_count_assignments_empl2 + 1)

    @patch(AUTHORIZE_ACTION_METHOD)
    def test_accept_decline_not_my_request(self, p_authorize):
        """
        Test accept or decline assign request if current user is not
        an approver in this request.
        Steps:
           - 1. Check initial count of incoming assignment requests for
             current user. Should be 0.
           - 2. Create assignment request for another user.
           - 3. Verify count of incoming requests. Should be 0.
           - 4. Verify count of outgoing requests. Should be 1.
           - 5. Try to accept created request. Forbidden.
           - 6. Verify no new assignments.
           - 7. Try to decline created request. Forbidden.
           - 8. Verify count of incoming/outgoing requests is the same.

        """
        requests = self._get_incoming_assignment_requests()
        self.assertEqual(len(requests), 0)
        new_request = self._prepare_assign_req_body(
            resource_id=self.resource['id'],
            approver_id=self.employee2['id'],
            message="Test message")
        p_authorize.return_value = True
        code, created = self.client.assignment_request_create(self.org_id,
                                                              new_request)
        self.assertEqual(code, 201)
        requests = self._get_incoming_assignment_requests()
        self.assertEqual(len(requests), 0)
        requests = self._get_outgoing_assignment_requests()
        self.assertEqual(len(requests), 1)
        code, _ = self.client.assignment_request_accept(
            created['id'], {'pool_id': self.org_pool_id})
        self.assertEqual(code, 403)
        assignments = self._get_assignments()
        self.assertEqual(len(assignments), self.initial_count_assignments_empl)
        code, _ = self.client.assignment_request_decline(created['id'])
        self.assertEqual(code, 403)
        requests = self._get_incoming_assignment_requests()
        self.assertEqual(len(requests), 0)
        requests = self._get_outgoing_assignment_requests()
        self.assertEqual(len(requests), 1)

    def test_decline_assignment(self):
        """
        Test decline existing incoming assignment request.
        Steps:
           - 1. Check initial count of incoming assignment requests for
             current user. Should be 0.
           - 2. Create assignment request for current user.
           - 3. Verify count of incoming requests. Should be 1.
           - 4. Decline assignment requests.
           - 5. Verify count of incoming requests. Should be 0.
           - 6. Verify count of assignments. Should be the same.

        """
        requests = self._get_incoming_assignment_requests()
        self.assertEqual(len(requests), 0)
        assignments = self._get_assignments()
        self.assertEqual(len(assignments), self.initial_count_assignments_empl)
        new_request = self._prepare_assign_req_body(
            resource_id=self.resource['id'],
            approver_id=self.employee2['id'],
            message="Test message")
        code, created = self.client.assignment_request_create(self.org_id,
                                                              new_request)
        self.assertEqual(code, 201)
        with self.switch_user(self.user2_id):
            requests = self._get_incoming_assignment_requests()
        self.assertEqual(len(requests), 1)
        p_publish_activity = patch(
            'rest_api.rest_api_server.controllers.base.BaseController.'
            'publish_activities_task'
        ).start()

        with self.switch_user(self.user2_id):
            code, _ = self.client.assignment_request_decline(created['id'])
        self.assertEqual(code, 204)
        requests = self._get_incoming_assignment_requests()
        self.assertEqual(len(requests), 0)
        activity_param_tuples = self.get_publish_activity_tuple(
            self.organization['id'], created['requester_id'], 'employee',
            'assignment_request_declined', ANY)
        self._check_notification_calls(p_publish_activity, 1,
                                       *activity_param_tuples,
                                       add_token=True)
        assignments = self._get_assignments()
        self.assertEqual(len(assignments), self.initial_count_assignments_empl)

    def test_decline_assignment_deleted_resource(self):
        """
        Test decline existing incoming assignment request.
        Steps:
           - 1. Check initial count of incoming assignment requests for
             current user. Should be 0.
           - 2. Create assignment request for current user.
           - 3. Verify count of incoming requests. Should be 1.
           - 4. Delete resource.
           - 4. Decline assignment requests.
           - 5. Verify count of incoming requests. Should be 0.
           - 6. Verify count of assignments. Should be the same.

        """
        assignments = self._get_assignments()
        self.assertEqual(len(assignments), self.initial_count_assignments_empl)
        requests = self._get_incoming_assignment_requests()
        self.assertEqual(len(requests), 0)
        new_request = self._prepare_assign_req_body(
            resource_id=self.resource['id'],
            approver_id=self.employee2['id'],
            message="Test message")
        code, created = self.client.assignment_request_create(self.org_id,
                                                              new_request)
        self.assertEqual(code, 201)
        with self.switch_user(self.user2_id):
            requests = self._get_incoming_assignment_requests()
        self.assertEqual(len(requests), 1)
        p_publish_activity = patch(
            'rest_api.rest_api_server.controllers.base.BaseController.'
            'publish_activities_task'
        ).start()
        self.client.cloud_resource_delete(self.resource['id'])

        with self.switch_user(self.user2_id):
            code, _ = self.client.assignment_request_decline(created['id'])
        self.assertEqual(code, 204)
        with self.switch_user(self.user2_id):
            requests = self._get_incoming_assignment_requests()
        self.assertEqual(len(requests), 0)
        activity_param_tuples = self.get_publish_activity_tuple(
            self.organization['id'], created['requester_id'], 'employee',
            'assignment_request_declined', ANY)
        self._check_notification_calls(p_publish_activity, 1,
                                       *activity_param_tuples,
                                       add_token=True)
        assignments = self._get_assignments()
        self.assertEqual(len(assignments), self.initial_count_assignments_empl)

    def test_decline_assignment_deleted_cc(self):
        """
        Test decline existing incoming assignment request.
        Steps:
           - 1. Check initial count of incoming assignment requests for
             current user. Should be 0.
           - 2. Create assignment request for current user.
           - 3. Verify count of incoming requests. Should be 1.
           - 4. Delete cc.
           - 4. Decline assignment requests.
           - 5. Verify count of incoming requests. Should be 0.
           - 6. Verify count of assignments. Should be the same.

        """
        assignments = self._get_assignments()
        self.assertEqual(len(assignments), self.initial_count_assignments_empl)
        requests = self._get_incoming_assignment_requests()
        self.assertEqual(len(requests), 0)
        new_request = self._prepare_assign_req_body(
            resource_id=self.resource['id'],
            approver_id=self.employee2['id'],
            message="Test message")
        code, created = self.client.assignment_request_create(self.org_id,
                                                              new_request)
        self.assertEqual(code, 201)
        with self.switch_user(self.user2_id):
            requests = self._get_incoming_assignment_requests()
        self.assertEqual(len(requests), 1)
        p_publish_activity = patch(
            'rest_api.rest_api_server.controllers.base.BaseController.'
            'publish_activities_task'
        ).start()
        self.client.cloud_account_delete(self.cloud_acc_id)

        with self.switch_user(self.user2_id):
            code, _ = self.client.assignment_request_decline(created['id'])
        self.assertEqual(code, 204)
        with self.switch_user(self.user2_id):
            requests = self._get_incoming_assignment_requests()
        self.assertEqual(len(requests), 0)
        activity_param_tuples = self.get_publish_activity_tuple(
            self.organization['id'], created['requester_id'], 'employee',
            'assignment_request_declined', ANY)
        self._check_notification_calls(p_publish_activity, 1,
                                       *activity_param_tuples,
                                       add_token=True)
        assignments = self._get_assignments()
        self.assertEqual(len(assignments), self.initial_count_assignments_empl)

    def test_cancel_assignment(self):
        """
        Test cancel existing outgoing assignment request.
        Steps:
           - 1. Check initial count of outgoing assignment requests for
             current user. Should be 0.
           - 2. Create assignment request for employee2.
           - 3. Verify count of outgoing requests. Should be 1.
           - 4. Switch to user2.
           - 5. Verify no assignments for employee2.
           - 6. Verify count of incoming requests. Should be 1
           - 7. Switch to user back.
           - 8. Cancel request.
           - 9. Verify count of outgoing requests. Should be 0.
           - 10. Switch to user2.
           - 11. Verify count of incoming requests. Should be 0
           - 12. Verify count of assignments. Should be 0.

        """
        requests = self._get_outgoing_assignment_requests()
        self.assertEqual(len(requests), 0)
        new_request = self._prepare_assign_req_body(
            resource_id=self.resource['id'],
            approver_id=self.employee2['id'],
            message="Test message")
        code, created = self.client.assignment_request_create(self.org_id,
                                                              new_request)
        self.assertEqual(code, 201)
        requests = self._get_outgoing_assignment_requests()
        self.assertEqual(len(requests), 1)

        with self.switch_user(self.user2_id):
            requests = self._get_incoming_assignment_requests()
            self.assertEqual(len(requests), 1)
            assignments = self._get_assignments()
            self.assertEqual(len(assignments), 0)
        code, _ = self.client.assignment_request_cancel(created['id'])
        self.assertEqual(code, 204)

        requests = self._get_outgoing_assignment_requests()
        self.assertEqual(len(requests), 0)
        with self.switch_user(self.user2_id):
            requests = self._get_incoming_assignment_requests()
            self.assertEqual(len(requests), 0)
            assignments = self._get_assignments()
            self.assertEqual(len(assignments), 0)

    @patch(AUTHORIZE_ACTION_METHOD)
    def test_cancel_not_my_request(self, p_authorize):
        """
        Test cancel assign request if current user is not a requester in this
        request.
        Steps:
           - 1. Check initial count of outgoing assignment requests for
             current user. Should be 0.
           - 2. Create assignment request for another user.
           - 3. Verify count of outgoing requests. Should be 1.
           - 4. Switch user to user2.
           - 5. Try to cancel created request. Forbidden.
           - 6. Verify count of incoming/outgoing requests is the same.

        """
        p_authorize.return_value = True
        requests = self._get_outgoing_assignment_requests()
        self.assertEqual(len(requests), 0)
        new_request = self._prepare_assign_req_body(
            resource_id=self.resource['id'],
            approver_id=self.employee2['id'],
            message="Test message")
        code, created = self.client.assignment_request_create(self.org_id,
                                                              new_request)
        self.assertEqual(code, 201)
        requests = self._get_outgoing_assignment_requests()
        self.assertEqual(len(requests), 1)
        with self.switch_user(self.user2_id):
            code, _ = self.client.assignment_request_cancel(created['id'])
            self.assertEqual(code, 403)
            requests = self._get_incoming_assignment_requests()
            self.assertEqual(len(requests), 1)
        requests = self._get_outgoing_assignment_requests()
        self.assertEqual(len(requests), 1)

    def test_params_create_assignment_req(self):
        """
        Test required parameters for creation assignment request.
        Steps:
           - 1. Verify requests without param:
             - resource_id
             - approver_id
           - 2. Verify requests with param, but entity doesn't exist:
             - resource_id
             - approver_id

        """
        new_request = self._prepare_assign_req_body(
            resource_id=self.resource['id'],
            approver_id=self.employee['id'],
            message="Test message")
        self._test_params(
            self.client.assignment_request_create, new_request, self.org_id,
            required_parameters=['resource_id', 'approver_id'],
            entities_should_exist=['resource_id', 'approver_id']
        )

    def test_params_create_assignment(self):
        """
        Test required parameters for creation assignment.
        Steps:
           - 1. Verify requests without param:
             - resource_id
             - pool_id
           - 2. Verify requests with param, but entity doesn't exist:
             - resource_id
             - owner_id
             - pool_id

        """
        new_request = self._prepare_assign_body(
            resource_id=self.resource['id'],
            pool_id=self.org_pool_id)
        self._test_params(
            self.client.assignment_create, new_request, self.org_id,
            required_parameters=['resource_id', 'pool_id'],
            entities_should_exist=['resource_id', 'owner_id', 'pool_id']
        )

    @patch(AUTHORIZE_ACTION_METHOD)
    def test_params_accept_assignment(self, p_authorize):
        """
        Test required parameters for accept assignment request.
        Steps:
           - 1. Verify requests without param:
             - action
             - pool_id
           - 2. Verify requests with param, but entity doesn't exist:
             - owner_id
             - pool_id
           - 3. Test accept request for another user

        """
        p_authorize.return_value = True
        requests = self._get_incoming_assignment_requests()
        self.assertEqual(len(requests), 0)
        new_request = self._prepare_assign_req_body(
            resource_id=self.resource['id'],
            approver_id=self.employee2['id'],
            message="Test message")
        code, created = self.client.assignment_request_create(self.org_id,
                                                              new_request)
        self.assertEqual(code, 201)
        with self.switch_user(self.user2_id):
            requests = self._get_incoming_assignment_requests()
        self.assertEqual(len(requests), 1)
        new_request = {
            'action': 'accept',
            'pool_id': self.org_pool_id,
            'owner_id': self.employee2['id']
        }
        with self.switch_user(self.user2_id):
            self._test_params(
                self.client.assignment_request_patch, new_request, created['id'],
                required_parameters=['action', 'pool_id'],
                entities_should_exist=['pool_id', 'owner_id']
            )
        with self.switch_user(self.user2_id):
            requests = self._get_incoming_assignment_requests()
        self.assertEqual(len(requests), 1)
        new_request = {
            'action': 'accept',
            'pool_id': self.org_pool_id,
            'owner_id': self.employee2['id']
        }
        code, resp = self.client.assignment_request_accept(created['id'],
                                                           new_request)
        self.assertEqual(code, 403)
        self.verify_error_code(resp, "OE0391")

    def test_params_decline_cancel_assignment(self):
        """
        Test parameters for decline/cancel assignment request.
        Steps:
           - 1. Verify unexpected params for decline/cancel flows including
             'message', 'created_at', 'pool_id', 'owner_id' they are expected
            for accept request action

        """
        requests = self._get_incoming_assignment_requests()
        self.assertEqual(len(requests), 0)
        new_request = self._prepare_assign_req_body(
            resource_id=self.resource['id'],
            approver_id=self.employee2['id'],
            message="Test message")
        code, created = self.client.assignment_request_create(self.org_id,
                                                              new_request)
        self.assertEqual(code, 201)
        with self.switch_user(self.user2_id):
            requests = self._get_incoming_assignment_requests()
        self.assertEqual(len(requests), 1)
        for action in ['decline', 'cancel']:
            for param in ['message', 'created_at', 'pool_id', 'owner_id',
                          "unexpected"]:
                code, resp = self.client.assignment_request_patch(
                    created['id'], {'action': action,
                                    param: 'test_value'}
                )
                self.assertEqual(code, 400)
                self.assertTrue(resp['error']['error_code'], 'OE0212')

    @patch(AUTHORIZE_ACTION_METHOD)
    def test_patch_assignment_req_bad_actions(self, p_authorize):
        """
        Test patch request without action provided
        Steps:
           - 1. Send patch request for existing assignment req:
             - without action
             - with unexpected action
             - with integer instead on string
             - with null value
           - 2. Verify 400 response code. Verify appropriate localized codes.

        """
        p_authorize.return_value = True
        requests = self._get_incoming_assignment_requests()
        self.assertEqual(len(requests), 0)
        new_request = self._prepare_assign_req_body(
            resource_id=self.resource['id'],
            approver_id=self.employee2['id'],
            message="Test message")
        code, created = self.client.assignment_request_create(self.org_id,
                                                              new_request)
        self.assertEqual(code, 201)
        with self.switch_user(self.user2_id):
            requests = self._get_incoming_assignment_requests()
        self.assertEqual(len(requests), 1)
        # no action
        code, resp = self.client.assignment_request_patch(created['id'], {})
        self.assertEqual(code, 400)
        self.verify_error_code(resp, 'OE0216')
        with self.switch_user(self.user2_id):
            requests = self._get_incoming_assignment_requests()
        self.assertEqual(len(requests), 1)
        # unexpected action
        code, resp = self.client.assignment_request_patch(
            created['id'],
            {'action': 'unexpected action'})
        self.assertEqual(code, 400)
        self.verify_error_code(resp, 'OE0166')
        with self.switch_user(self.user2_id):
            requests = self._get_incoming_assignment_requests()
        self.assertEqual(len(requests), 1)
        # integer action
        code, resp = self.client.assignment_request_patch(
            created['id'],
            {'action': 123})
        self.assertEqual(code, 400)
        self.verify_error_code(resp, 'OE0214')
        with self.switch_user(self.user2_id):
            requests = self._get_incoming_assignment_requests()
        self.assertEqual(len(requests), 1)
        # null action
        code, resp = self.client.assignment_request_patch(
            created['id'],
            {'action': None})
        self.assertEqual(code, 400)
        self.verify_error_code(resp, 'OE0216')
        with self.switch_user(self.user2_id):
            requests = self._get_incoming_assignment_requests()
        self.assertEqual(len(requests), 1)

    def test_assign_request_not_exist(self):
        """
        Test decline assignment request that doesn't exist.
        Steps:
           - 1. Try to decline assignment request with random number.
           - 2. Verify response code is 404.

        """
        unexpected_id = self.gen_id()
        code, response = self.client.assignment_request_decline(unexpected_id)
        self.assertEqual(code, 404)
        self.assertEqual(
            response['error']['reason'],
            "AssignmentRequest %s not found" % unexpected_id)

    @patch(AUTHORIZE_ACTION_METHOD)
    def test_assignment_is_already_exist(self, p_authorize):
        """
        Test create assignment for resource that is already assigned.
        Steps:
           - 1. Check initial count of assignments for user.
           - 2. Create assignment for current user.
           - 3. Verify response code is 201.
           - 5. Create assignment for current user for different resource.
           - 4. Verify count of assignments is +1.
           - 5. Create assignment for current user for the same resource.
           - 6. Verify response code is 201.
           - 7. Verify count of assignments is still +1.

        """
        assignments = self._get_assignments()
        self.assertEqual(len(assignments), self.initial_count_assignments_empl)
        resource2 = self._create_resource(employee_id=self.employee['id'],
                                          pool_id=self.org_pool_id)
        new_request = self._prepare_assign_body(
            resource_id=resource2['id'],
            pool_id=self.sub_pools[0]['id'])
        p_authorize.return_value = True
        code, _ = self.client.assignment_create(self.org_id, new_request)
        self.assertEqual(code, 201)
        assignments = self._get_assignments()
        self.assertEqual(len(assignments),
                         self.initial_count_assignments_empl + 1)

        new_request1 = self._prepare_assign_body(
            resource_id=self.resource['id'],
            pool_id=self.sub_pools[1]['id'])
        code, _ = self.client.assignment_create(self.org_id,
                                                new_request1)
        self.assertEqual(code, 201)
        assignments = self._get_assignments()
        self.assertEqual(len(assignments),
                         self.initial_count_assignments_empl + 1)

    @patch(AUTHORIZE_ACTION_METHOD)
    def test_accept_assignment(self, p_authorize):
        """
        Test accept assignment basic flow.
        Steps:
           - 1. Check initial count of assignment requests for current user.
             Should be 0.
           - 2. Create assignment request for current user.
           - 3. Verify count of incoming assignments is 1.
           - 4. Accept assignment request with valid parameters.
           - 5. Verify response code is 204.
           - 6. Verify count of incoming assignments is 0.
           - 7. Verify count of assignments is 1 for employee_2.
           - 8. Verify new assignment. It should has provided parameters.
           - 9. Verify count of assignments is 0 for employee_1.

        """
        requests = self._get_incoming_assignment_requests()
        self.assertEqual(len(requests), 0)
        new_request = self._prepare_assign_req_body(
            resource_id=self.resource['id'],
            approver_id=self.employee2['id'],
            message="Test message")
        p_authorize.return_value = True
        code, created = self.client.assignment_request_create(self.org_id,
                                                              new_request)
        self.assertEqual(code, 201)
        with self.switch_user(self.user2_id):
            requests = self._get_incoming_assignment_requests()
        self.assertEqual(len(requests), 1)
        p_publish_activity = patch(
            'rest_api.rest_api_server.controllers.base.BaseController.'
            'publish_activities_task'
        ).start()
        p_validate_resource = patch(
            'rest_api.rest_api_server.controllers.assignment'
            '.AssignmentController.validate_resource').start()
        with self.switch_user(self.user2_id):
            code, _ = self.client.assignment_request_accept(
                created['id'], {'pool_id': self.org_pool_id})
        self.assertEqual(code, 204)
        self.assertFalse(p_validate_resource.called)
        requests = self._get_incoming_assignment_requests()
        self.assertEqual(len(requests), 0)
        activity_param_tuples = self.get_publish_activity_tuple(
            self.organization['id'], created['requester_id'], 'employee',
            'assignment_request_accepted', ANY)
        self._check_notification_calls(p_publish_activity, 1,
                                       *activity_param_tuples,
                                       add_token=True)
        with self.switch_user(self.user2_id):
            assignments = self._get_assignments()
            self.assertEqual(len(assignments), 1)
            created_assignment = assignments[0]
            self._check_response(created_assignment,
                                 resource_id=self.resource['id'],
                                 pool_id=self.org_pool_id,
                                 owner_id=self.employee2['id'])
        assignments = self._get_assignments()
        self.assertEqual(len(assignments), 0)

    @patch(AUTHORIZE_ACTION_METHOD)
    def test_accept_assignment_for_deleted_resource(self, p_authorize):
        """
        Test accept assignment if the target resource is already deleted.
        Steps:
           - 1. Check initial count of assignment requests for current user.
             Should be 0.
           - 2. Create assignment request for current user.
           - 3. Verify count of incoming assignments is 1.
           - 4. Delete the target resource.
           - 5. Try to accept created assignment request.
           - 6. Verify response code, should be 400.
           - 7. Verify count of incoming requests and assignments.
             Should be the same.

        """
        assignments = self._get_assignments()
        self.assertEqual(len(assignments), self.initial_count_assignments_empl)
        requests = self._get_incoming_assignment_requests()
        self.assertEqual(len(requests), 0)
        new_request = self._prepare_assign_req_body(
            resource_id=self.resource['id'],
            approver_id=self.employee['id'],
            message="Test message")
        p_authorize.return_value = True
        with self.switch_user(self.user2_id):
            code, created = self.client.assignment_request_create(self.org_id,
                                                                  new_request)
        self.assertEqual(code, 201)
        requests = self._get_incoming_assignment_requests()
        self.assertEqual(len(requests), 1)
        self.client.cloud_resource_delete(self.resource['id'])
        code, _ = self.client.assignment_request_accept(
            created['id'], {'pool_id': self.org_pool_id})
        self.assertEqual(code, 400)
        requests = self._get_incoming_assignment_requests()
        self.assertEqual(len(requests), 1)
        assignments = self._get_assignments()
        self.assertEqual(len(assignments), self.initial_count_assignments_empl)

    @patch(AUTHORIZE_ACTION_METHOD)
    def test_accept_decline_assignment_for_deleted_resource(self, p_authorize):
        """
        Test accept/decline assignment if the target resource is
        already deleted.
        Steps:
           - 1. Check initial count of assignment requests for current user.
             Should be 0.
           - 2. Create assignment request for current user.
           - 3. Verify count of incoming assignments is 1.
           - 4. Delete the target resource.
           - 5. Try to accept created assignment request.
           - 6. Verify response code, should be 400.
           - 7. Verify count of incoming requests and assignments.
             Should be the same.
           - 8. Try to decline created assignment request. Should pass.
           - 9. Verify count of incoming requests. Should be 0.

        """
        requests = self._get_incoming_assignment_requests()
        self.assertEqual(len(requests), 0)
        new_request = self._prepare_assign_req_body(
            resource_id=self.resource['id'],
            approver_id=self.employee['id'],
            message="Test message")
        p_authorize.return_value = True
        with self.switch_user(self.user2_id):
            code, created = self.client.assignment_request_create(self.org_id,
                                                                  new_request)
        self.assertEqual(code, 201)
        requests = self._get_incoming_assignment_requests()
        self.assertEqual(len(requests), 1)
        self.client.cloud_resource_delete(self.resource['id'])
        code, _ = self.client.assignment_request_accept(
            created['id'], {'pool_id': self.org_pool_id})
        self.assertEqual(code, 400)
        requests = self._get_incoming_assignment_requests()
        self.assertEqual(len(requests), 1)
        assignments = self._get_assignments()
        self.assertEqual(len(assignments), self.initial_count_assignments_empl)
        code, _ = self.client.assignment_request_decline(created['id'])
        self.assertEqual(code, 204)
        requests = self._get_incoming_assignment_requests()
        self.assertEqual(len(requests), 0)
        assignments = self._get_assignments()
        self.assertEqual(len(assignments), self.initial_count_assignments_empl)

    @patch(AUTHORIZE_ACTION_METHOD)
    def test_create_assignments_request_no_permissions_resource(self,
                                                                p_authorize):
        """
        Test creation assignment request for resource without permissions on
        this resource.
        Steps:
           - 1. Verify count of incoming requests. Should be 0.
           - 2. Try to create assignment request for resource where current
             user is not an owner and no MANAGE_RESOURCE permission on the
             source BU where resource located.
           - 3. Verify response code is 403 Forbidden.
           - 4. Verify no new incoming requests for target user.

        """
        p_authorize.return_value = False
        new_request = self._prepare_assign_req_body(
            resource_id=self.resource['id'],
            approver_id=self.employee['id'],
            message="Test message")
        with self.switch_user(self.user2_id):
            requests = self._get_incoming_assignment_requests()
            self.assertEqual(len(requests), 0)
            code, resp = self.client.assignment_request_create(self.org_id,
                                                               new_request)
            self.assertEqual(code, 403)
            self.verify_error_code(resp, 'OE0381')
        requests = self._get_incoming_assignment_requests()
        self.assertEqual(len(requests), 0)

    @patch(AUTHORIZE_ACTION_METHOD)
    def test_create_assignments_no_permissions_resource(self, p_authorize):
        """
        Test creation assignment for resource without permissions on this
        resource.
        Steps:
           - 1. Verify count of assignments for current user. Should be 0.
           - 2. Try to create assignment for resource where current
             user is not an owner and no MANAGE_RESOURCE permission on the
             source BU where resource located.
           - 3. Verify response code is 403 Forbidden.
           - 4. Verify no new assignments for target user.

        """
        p_authorize.return_value = False
        with self.switch_user(self.user2_id):
            requests = self._get_assignments()
            self.assertEqual(len(requests), 0)
            new_request = self._prepare_assign_body(
                resource_id=self.resource['id'],
                pool_id=self.org_pool_id)

            code, resp = self.client.assignment_create(self.org_id,
                                                       new_request)
            self.assertEqual(code, 403)
            self.verify_error_code(resp, 'OE0381')
            requests = self._get_assignments()
            self.assertEqual(len(requests), 0)

    @patch(AUTHORIZE_ACTION_METHOD)
    def test_create_assignments_no_permissions_pool(self, p_authorize):
        """
        Test creation assignment for resource without permissions on target
        pool.
        Steps:
           - 1. Verify count of assignments for current user. Should be 0.
           - 2. Try to create assignment for resource if current
             user doesn't have permission on the target pool.
           - 3. Verify response code is 403 Forbidden.
           - 4. Verify no new assignments for target user.

        """
        with self.switch_user(self.user2_id):
            requests = self._get_assignments()
            self.assertEqual(len(requests), 0)
            new_request = self._prepare_assign_body(
                resource_id=self.resource['id'],
                pool_id=self.org_pool_id)
            p_authorize.side_effect = [True, False]
            code, resp = self.client.assignment_create(self.org_id,
                                                       new_request)
            self.assertEqual(code, 403)
            self.verify_error_code(resp, 'OE0380')
            assignments = self._get_assignments()
            self.assertEqual(len(assignments), 0)

    @patch(AUTHORIZE_ACTION_METHOD)
    def test_create_assignments_no_permissions_owner(self, p_authorize):
        """
        Test creation assignment for resource if target owner doesn't have
        permissions in target pool.
        Steps:
           - 1. Verify count of assignments for current user. Should be 0.
           - 2. Try to create assignment for resource if target owner
             doesn't have permission on the target pool.
           - 3. Verify response code is 403 Forbidden.
           - 4. Verify no new assignments for target user.

        """
        with self.switch_user(self.user2_id):
            assignments = self._get_assignments()
            self.assertEqual(len(assignments), 0)
            new_request = self._prepare_assign_body(
                resource_id=self.resource['id'],
                pool_id=self.org_pool_id)
            p_authorize.side_effect = [True, True, False]
            code, resp = self.client.assignment_create(self.org_id,
                                                       new_request)
            self.assertEqual(code, 403)
            self.verify_error_code(resp, 'OE0379')
            assignments = self._get_assignments()
            self.assertEqual(len(assignments), 0)

    @patch(AUTHORIZE_ACTION_METHOD)
    def test_split_resources(self, p_authorize):
        """
        Basic split resources flow.
        Steps:
           - 1. Create the following types of resources:
             - 1 assigned resource to cur user
             - 2 assigned resources to another user
             - 1 cluster subresource
           - 2. Create assignment request for 1 owned resource and 1 managed.
           - 3. Request split resource API.
           - 4. Setup auth client to return all auth requests as False
           - 5. Verify response code is 200.
           - 6. Verify count of resources in response is 5.
           - 7. Verify 2 users_own resource,
             no manageable resources and 2 restricted resources
           - 8. Verify all resources has 'has_active_transfer' filled.
           - 9. Verify 'has_active_transfer' filled for all resources
             - it should be true for resources from step 2, false otherwise.
           - 10. Setup auth client to return all auth requests as True
           - 11. Verify response code is 200.
           - 12. Verify count of resources in response is 5.
           - 13. Verify 2 users_own resource,
             no restricted resources and 2 manageable resources.

        """
        res_ids_for_requests = []
        user_own_resource = self._create_resource(
            employee_id=self.employee['id'], pool_id=self.org_pool_id)
        res_ids_for_requests.append(user_own_resource['id'])
        another_own_resource1 = self._create_resource(
            employee_id=self.employee2['id'], pool_id=self.org_pool_id
        )
        res_ids_for_requests.append(another_own_resource1['id'])
        another_own_resource2 = self._create_resource(
            employee_id=self.employee2['id'], pool_id=self.org_pool_id
        )
        clustered_resource = self._create_resource(
            tags={'tn': 'tv'}
        )
        p_authorize.return_value = True
        for res_id in res_ids_for_requests:
            new_request = self._prepare_assign_req_body(
                resource_id=res_id,
                approver_id=self.employee2['id'])
            code, _ = self.client.assignment_request_create(self.org_id,
                                                            new_request)
            self.assertEqual(code, 201)
        with self.switch_user(self.user2_id):
            requests = self._get_incoming_assignment_requests()
        self.assertEqual(len(requests), 2)
        code, resp = self.client.split_resources(
            self.org_id,
            [user_own_resource['id'],
             another_own_resource1['id'],
             another_own_resource2['id'],
             clustered_resource['cluster_id']])
        self.assertEqual(code, 200)
        self.assertEqual(resp['owned'][0]['pool_purpose'], 'business_unit')
        self.assertEqual(len(resp['owned']), 2)
        self.assertEqual(len(resp['managed']), 2)
        for type_ in resp.keys():
            for res in resp[type_]:
                self.assertTrue('has_active_transfer' in res)
                if res['has_active_transfer']:
                    self.assertTrue(res['resource_id'] in res_ids_for_requests)
                else:
                    self.assertFalse(res['resource_id'] in res_ids_for_requests)
        self.assertEqual(
            {another_own_resource1['id'],
             another_own_resource2['id']},
            set([res['resource_id'] for res in resp['managed']]))
        self.assertEqual(len(resp['restricted']), 0)
        p_authorize.return_value = False
        code, resp = self.client.split_resources(
            self.org_id,
            [user_own_resource['id'],
             another_own_resource1['id'],
             another_own_resource2['id'],
             clustered_resource['cluster_id']])
        self.assertEqual(code, 200)
        self.assertEqual(len(resp['owned']), 2)
        self.assertEqual(len(resp['managed']), 0)
        self.assertEqual(len(resp['restricted']), 2)
        self.assertEqual(
            {another_own_resource1['id'],
             another_own_resource2['id']},
            set([res['resource_id'] for res in resp['restricted']]))

    def test_split_deleted_resources(self):
        """
        Basic split resources flow.
        Steps:
           - 1. Create the following types of resources:
             - 1 assigned resource to cur user
           - 2. Request split resource API.
           - 3. Verify count of resources in response is 1 and it's owned
             resource.
           - 4. Delete created resource
           - 5. Repeat step 2
           - 6. Verify response code is 200.
           - 7. Verify count of resources in response is 0.

        """
        user_own_resource = self._create_resource(
            employee_id=self.employee['id'], pool_id=self.org_pool_id)
        code, resp = self.client.split_resources(
            self.org_id, [user_own_resource['id']])
        self.assertEqual(code, 200)
        self.assertEqual(len(resp['owned']), 1)
        self.assertEqual(resp['owned'][0]['resource_id'],
                         user_own_resource['id'])
        self.assertEqual(len(resp['managed']), 0)
        self.assertEqual(len(resp['restricted']), 0)
        self.client.cloud_resource_delete(user_own_resource['id'])

        code, resp = self.client.split_resources(
            self.org_id, [user_own_resource['id']])
        self.assertEqual(code, 200)
        self.assertEqual(len(resp['owned']), 0)
        self.assertEqual(len(resp['managed']), 0)
        self.assertEqual(len(resp['restricted']), 0)

    def test_split_subresource(self):
        """
        Basic split resources flow.
        Steps:
           - 1. Create the following types of resources:
             - 1 cluster subresource
           - 2. Request split resource API.
           - 3. Verify count of resources in response is 0.
        """
        code, _ = self.client.cluster_type_create(
            self.org_id, {'name': 'c_type', 'tag_key': 'tn'})
        clustered_resource = self._create_resource(tags={'tn': 'tv'})
        code, resp = self.client.split_resources(
            self.org_id, [clustered_resource['id']])
        self.assertEqual(code, 200)
        for val in resp.values():
            self.assertListEqual(val, [])

    def test_split_invalid_resources(self):
        """
        Basic split resources flow.
        Steps:
           - 1. Request split resource API with invalid resource ids
           - 2. Verify response code is 200.
           - 3. Verify count of resources in response is 0.

        """
        invalid_ids = [self.gen_id() for _ in range(10)]
        code, resp = self.client.split_resources(self.org_id, invalid_ids)
        self.assertEqual(code, 200)
        self.assertEqual(len(resp['owned']), 0)
        self.assertEqual(len(resp['managed']), 0)
        self.assertEqual(len(resp['restricted']), 0)

    def test_split_valid_resources_from_another_org(self):
        """
        Basic split resources flow.
        Steps:
           - 1. Create one more organization. Org2.
           - 2. Create cloud account for this organization.
           - 3. Create resource for this organization.
           - 4. Request split resource API with resource ids from new
             organization, if cur org in the first one.
           - 3. Verify count of resources in response is 0.

        """
        code, organization2_bu = self.client.organization_create(
            {'name': "new_organization"})
        self.assertEqual(code, 201)
        user_id = self.gen_id()
        org2_bu_id = organization2_bu['id']
        self._create_employee(user_id, org2_bu_id)
        valid_aws_cloud_acc = {
            'name': 'test_credentials2',
            'type': 'aws_cnr',
            'config': {
                'access_key_id': 'key',
                'secret_access_key': 'secret',
                'config_scheme': 'create_report'
            }
        }
        code, cloud_acc = self.create_cloud_account(
            org2_bu_id, valid_aws_cloud_acc, auth_user_id=user_id)
        self.assertEqual(code, 201)
        cloud_acc_id = cloud_acc['id']
        valid_resource = {
            'cloud_resource_id': self.gen_id(),
            'name': 'test_resource',
            'resource_type': 'test_type',
            'employee_id': None,
            'pool_id': None
        }
        code, resource = self.cloud_resource_create(
            cloud_acc_id, valid_resource)
        self.assertEqual(code, 201)

        code, resp = self.client.split_resources(self.org_id,
                                                 [resource['id']])
        self.assertEqual(code, 200)
        self.assertEqual(len(resp['owned']), 0)
        self.assertEqual(len(resp['managed']), 0)
        self.assertEqual(len(resp['restricted']), 0)

    def test_split_invalid_body(self):
        """
        Basic tests for invalid request body
        Steps:
           - 1. Request split resource API with json object in body instead of
             array.
           - 2. Verify response code is 400.
           - 3. Request split resource API with array of ints.
           - 4. Verify response code is 400.
           - 4. Request split resource API without body.
           - 4. Verify response code is 400.

        """
        code, _ = self.client.split_resources(self.org_id, {"id": "123"})
        self.assertEqual(code, 400)
        code, _ = self.client.split_resources(self.org_id, [1, 2, 3])
        self.assertEqual(code, 400)
        code, _ = self.client.split_resources(self.org_id, None)
        self.assertEqual(code, 400)

    def test_request_invalidation_by_creating_new_one(self):
        """
        Test request invalidation by creating new assignment request
        Steps:
           - 1. Check initial count of assignment requests for user.
             Should be 0.
           - 2. Create assignment request for current user.
           - 3. Verify response code is 201.
           - 4. Verify count of incoming assignment requests is 1.
           - 5. Create assignment request for current user.
           - 6. Verify response code is 201.
           - 7. Verify count of incoming assignment requests is still 1.
             - verify that request id is the new one

        """
        requests = self._get_incoming_assignment_requests()
        self.assertEqual(len(requests), 0)
        new_request = self._prepare_assign_req_body(
            resource_id=self.resource['id'],
            approver_id=self.employee2['id'],
            message="Test message")
        code, _ = self.client.assignment_request_create(self.org_id,
                                                        new_request)
        self.assertEqual(code, 201)
        with self.switch_user(self.user2_id):
            requests = self._get_incoming_assignment_requests()
        self.assertEqual(len(requests), 1)
        old_req_id = requests[0]['id']
        code, _ = self.client.assignment_request_create(self.org_id,
                                                        new_request)
        self.assertEqual(code, 201)
        with self.switch_user(self.user2_id):
            requests = self._get_incoming_assignment_requests()
        self.assertEqual(len(requests), 1)
        new_req_id = requests[0]['id']
        self.assertNotEqual(old_req_id, new_req_id)

    @patch(AUTHORIZE_ACTION_METHOD)
    def test_request_invalidation_by_direct_assign(self, p_authorize):
        """
        Test request invalidation by creating new assignment
        Steps:
           - 1. Check initial count of assignment requests for user.
             Should be 0.
           - 2. Create assignment request for current user.
           - 3. Verify response code is 201.
           - 4. Verify count of incoming assignment requests is 1.
           - 5. Do direct assign for this resource.
           - 6. Verify response code is 201.
           - 7. Verify count of incoming assignment requests is 0.

        """
        p_authorize.return_value = True
        requests = self._get_incoming_assignment_requests()
        self.assertEqual(len(requests), 0)
        new_request = self._prepare_assign_req_body(
            resource_id=self.resource['id'],
            approver_id=self.employee2['id'],
            message="Test message")
        code, _ = self.client.assignment_request_create(self.org_id,
                                                        new_request)
        self.assertEqual(code, 201)
        with self.switch_user(self.user2_id):
            requests = self._get_incoming_assignment_requests()
        self.assertEqual(len(requests), 1)
        new_request = self._prepare_assign_body(
            resource_id=self.resource['id'],
            pool_id=self.org_pool_id,
            owner_id=self.employee2['id'])
        p_authorize.return_value = True
        code, _ = self.client.assignment_create(self.org_id, new_request)
        self.assertEqual(code, 201)
        with self.switch_user(self.user2_id):
            requests = self._get_incoming_assignment_requests()
        self.assertEqual(len(requests), 0)

    @patch(AUTHORIZE_ACTION_METHOD)
    def test_req_invalidation_by_direct_assign_with_idempotency(self,
                                                                p_authorize):
        """
        Test request invalidation by creating new assignment request in case of
        idempotent assign
        Steps:
           - 1. Check initial count of assignment requests for user.
             Should be 0.
           - 2. Create assignment request for current user.
           - 3. Verify response code is 201.
           - 4. Verify count of incoming assignment requests is 1.
           - 5. Check count of assignments for current user. Should be 1.
           - 6. Do direct assign for this resource to the same user and the same
             pool
           - 7. Verify response code is 201.
           - 8. Verify count of assignments for the current user is still 1.
             - verify it's the same assignment as in step 5.
           - 9. Verify count of incoming assignment requests is 0.

        """
        p_authorize.return_value = True
        requests = self._get_incoming_assignment_requests()
        self.assertEqual(len(requests), 0)
        new_request = self._prepare_assign_req_body(
            resource_id=self.resource['id'],
            approver_id=self.employee2['id'],
            message="Test message")
        code, _ = self.client.assignment_request_create(self.org_id,
                                                        new_request)
        self.assertEqual(code, 201)
        with self.switch_user(self.user2_id):
            requests = self._get_incoming_assignment_requests()
        self.assertEqual(len(requests), 1)
        assignments = self._get_assignments()
        self.assertEqual(len(assignments), 1)
        new_request = self._prepare_assign_body(
            resource_id=self.resource['id'],
            pool_id=self.org_pool_id,
            owner_id=self.employee['id'])
        p_authorize.return_value = True
        code, _ = self.client.assignment_create(self.org_id, new_request)
        self.assertEqual(code, 201)
        assignments = self._get_assignments()
        self.assertEqual(len(assignments), 1)
        self.assertEqual(assignments[0], {
            'resource_id': self.resource['id'],
            'pool_id': self.org_pool_id,
            'owner_id': self.employee['id']
        })
        requests = self._get_incoming_assignment_requests()
        self.assertEqual(len(requests), 0)

    def test_create_assignment_request_for_the_same_user(self):
        requests = self._get_incoming_assignment_requests()
        self.assertEqual(len(requests), 0)
        new_request = self._prepare_assign_req_body(
            resource_id=self.resource['id'],
            approver_id=self.employee['id'],
            message="Test message")
        code, response = self.client.assignment_request_create(self.org_id,
                                                               new_request)
        self.assertEqual(code, 403)
        self.verify_error_code(response, 'OE0424')

    @patch(AUTHORIZE_ACTION_METHOD)
    def test_assignment_event(self, p_authorize):
        user_info = {
            'display_name': 'John Smth', 'id': self._user_id,
            'email': 'example@hystax.com'
        }
        self.p_get_user_info.return_value = user_info
        p_publish_activity = patch(
            'rest_api.rest_api_server.controllers.base.BaseController.'
            'publish_activities_task'
        ).start()
        resource = self._create_resource()
        assignments = self._get_assignments()
        self.assertEqual(len(assignments),
                         self.initial_count_assignments_empl + 1)
        new_request = self._prepare_assign_body(
            resource_id=resource['id'],
            pool_id=self.org_pool_id)
        p_authorize.return_value = True
        code, _ = self.client.assignment_create(self.org_id, new_request)
        self.assertEqual(code, 201)
        activity_param_tuples = self.get_publish_activity_tuple(
            self.org_id, self.organization['pool_id'], 'pool',
            'resource_assigned', ANY)
        self._check_notification_calls(p_publish_activity, 1,
                                       *activity_param_tuples,
                                       add_token=True)

    @patch(AUTHORIZE_ACTION_METHOD)
    def test_history_rewrite_resources_clustered(self, p_authorize):
        """
        Test expenses recalculating if history was rewritten.
        Steps:
           - 1. Create 1 expense for cluster dependent resource in the day1 in
           the past.
           - 2. Create 1 expenses for cluster dependent resources in the day2
           in the past. After day1.
           - 3. Check expenses, 2 expenses + 1 initial should be with owner and
           pool.
        """
        p_authorize.return_value = True

        clustered_resource = self._create_resource(tags={'tn': 'tv'})
        resources = self._get_resources({'_id': clustered_resource['id']})
        self.assertEqual(len(resources), 1)
        for resource in resources:
            self.assertEqual(resource.get('pool_id'), self.org_pool_id)
            self.assertEqual(resource.get('employee_id'), self.employee['id'])

        new_request = self._prepare_assign_body(
            resource_id=clustered_resource['cluster_id'],
            pool_id=self.sub_pools[0]['id'])
        code, _ = self.client.assignment_create(self.org_id, new_request)
        self.assertEqual(code, 201)
        resources = self._get_resources({'_id': clustered_resource['id']})
        self.assertEqual(len(resources), 1)
        for resource in resources:
            self.assertEqual(resource['pool_id'], self.sub_pools[0]['id'])
            self.assertEqual(resource['employee_id'], self.employee['id'])
